﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using SafeScript.MetaModel;
using SafeScript.MetaModel.Statements;
using SafeScript.Generator;
using PerCederberg.Grammatica.Runtime;

namespace SafeScript.Debugger
{
    public class DebugFileHyperlink
    {
        public Node Node;
        public MemberFunction Function;
        public string JSCode;
    }

    public class DebugFileGenerator
    {
        private Compiler compiler;
        private string filename;
        private StreamWriter writer;
        private List<DebugFileHyperlink> hyperlinks = new List<DebugFileHyperlink>();
        private JavaScriptGenerator jsGenerator;

        public DebugFileGenerator(Compiler compiler, string filename)
        {
            this.compiler = compiler;
            this.filename = filename;
        }

        public void Generate(ErrorReport report)
        {
            try
            {
                FileStream stream = new FileStream(this.filename, FileMode.Create);
                using (this.writer = new StreamWriter(stream))
                {
                }
            }
            catch (IOException ex)
            {
                report.Add(new ErrorEntry(ex, this.filename));
                return;
            }
        }

        public void Parse(Namespace nspace, JavaScriptGenerator jsGenerator)
        {
            this.jsGenerator = jsGenerator;

            foreach (object o in nspace.ScopeElements.Values)
            {
                if (o is Namespace)
                {
                    // Recursion
                    this.Parse(o as Namespace, this.jsGenerator);
                }
                else if (o is MemberFunction)
                {
                    this.ParseMemberFunction(o as MemberFunction);
                }
            }
        }

        private void ParseMemberFunction(MemberFunction memberFunction)
        {
            if (memberFunction.Statements == null)
                return;

            this.ParseStatements(memberFunction, memberFunction.Statements);
        }

        private void ParseStatements(MemberFunction memberFunction, StatementList statements)
        {
            foreach (Statement s in statements)
            {
                if (s is VarStatement)
                {
                    VarStatement v = s as VarStatement;
                    if ( v.InitialValue != null )
                        this.ParseExpression(memberFunction, v.InitialValue);

                    this.hyperlinks.Add( new DebugFileHyperlink() { Function = memberFunction, Node = memberFunction.Node, JSCode = this.jsGenerator.Ident(v) });
                }
                else if (s is ExpressionStatement)
                {
                }
                else if (s is ForEachStatement)
                {
                }
                else if (s is ForStatement)
                {
                }
                else if (s is WhileStatement)
                {
                }
                else if (s is IfStatement)
                {
                }
                else if (s is YieldReturnStatement)
                {
                }
                else if (s is ReturnStatement)
                {
                }
                else if (s is TryStatement)
                {
                }
                else if (s is CatchStatement)
                {
                }
                else if (s is ThrowStatement)
                {
                }
            }
        }

        private void ParseExpression(MemberFunction memberFunction, Operator op)
        {
            if (op is Atom)
            {
                Atom a = op as Atom;
                switch (a.Kind)
                {
                    case AtomKind.IDENTIFIER:
                        // TODO
                        break;
                    case AtomKind.SUPER:
                        // TODO
                        break;
                    case AtomKind.THIS:
                        // TODO
                        break;
                    case AtomKind.VALUE:
                        // TODO
                        break;
                }
            }
            else if (op is PropertyOperator)
            {
            }
            else if (op is BinaryOperator)
            {
            }
            // TODO: Follow other operators, too
        }
    }
}
